package com.kc.gb.device.plugins.slant.utils;

import com.kc.gb.device.plugins.slant.dto.SlantFeedbackMessage;
import com.kc.gb.device.plugins.slant.dto.SlantState;
import com.kc.gb.feign.slant.support.SlantCommandType;
import com.kc.gb.feign.slant.support.StationPointLayout;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.nio.ByteBuffer;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class SlantUtils {

    private static final Map<String, Integer> idMap = new HashMap<>();
    private static final Map<String, String> lockObject = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        String data = "AA10123400002121003B000000007D55";
        log.info("decode:{}", parseFromSlantCallback(data));

        String stationCode = "Station_5";
        StationPointLayout position = StationPointLayout.left;
        String command = build2SlantDeviceCommand(stationCode,position, SlantCommandType.Lower);
        log.info("encode:{}", command);
    }

    /**
     * 斜顶指令封装
     * @param stationCode
     * @param position
     * @param slantDeviceCommandType
     * @return
     */
    public static String build2SlantDeviceCommand(String stationCode, StationPointLayout position, SlantCommandType slantDeviceCommandType) {
        //SlantDeviceCommandType[] slantStationDeviceCommandTypes = new SlantDeviceCommandType[]{slantDeviceCommandType};
        SlantCommandType slantStationDeviceCommandType = slantDeviceCommandType;
        byte[] byteRequest = new byte[16];
        //1 设置帧头 byte0
        byteRequest[0] = Integer.valueOf(0xAA).byteValue();
        //2 设置报文总长度 byte1
        byteRequest[1] = Integer.valueOf(0x10).byteValue();
        //3 设置时间戳
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 获取当天的起始时间（即当天的00:00:00）
        LocalDateTime startOfDay = now.toLocalDate().atStartOfDay();
        // 计算从当天开始到当前时间的持续时间
        Duration duration = Duration.between(startOfDay, now);
        // 获取持续时间中的秒数
        long passed2SecondsOfToday = duration.getSeconds() / 2;
        ByteBuffer buffer = ByteBuffer.allocate(8);
        buffer.putLong(passed2SecondsOfToday);
        byte[] dateByteArray = buffer.array();
        //时间戳(预留 目前固定0X00) byte2,3
        byteRequest[2] = dateByteArray[6];
        //时间戳(预留 目前固定0X00) byte2,3
        byteRequest[3] = dateByteArray[7];
        //4 设置端口
        //端口 byte4,5
        byteRequest[4] = Integer.valueOf(0x20).byteValue();
        //端口 byte4,5
        byteRequest[5] = Integer.valueOf(0x00).byteValue();
        //5 设置datatype
        //datatype  0X21XX byte6,7
        byteRequest[6] = Integer.valueOf(0x21).byteValue();
        //0X20:设置辊筒运行状态
        byteRequest[7] = Integer.valueOf(0x20).byteValue();
        //6 设置CMD_ID:每发一次递增1 byte8
        int cmdId = getNextId(stationCode, 255);
        buffer = ByteBuffer.allocate(4);
        buffer.putInt(cmdId);
        byte[] idByteArray = buffer.array();
        byteRequest[8] = idByteArray[3];
        //数据值 byte9,byte10,byte11,byte12,byte13
        if (position == StationPointLayout.left) {
            if (SlantCommandType.OpenAutoLift == slantStationDeviceCommandType) {
                byteRequest[9] = Integer.valueOf(0X0A).byteValue();
            } else if (SlantCommandType.Lift == slantStationDeviceCommandType) {
                byteRequest[9] = Integer.valueOf(0X01).byteValue();
            } else {
                byteRequest[9] = Integer.valueOf(0X02).byteValue();
            }
        } else {
            if (SlantCommandType.OpenAutoLift == slantStationDeviceCommandType) {
                byteRequest[9] = Integer.valueOf(0X0B).byteValue();
            } else if (SlantCommandType.Lift == slantStationDeviceCommandType) {
                byteRequest[9] = Integer.valueOf(0X04).byteValue();
            } else {
                byteRequest[9] = Integer.valueOf(0X05).byteValue();
            }
        }
        //数据值 byte9,byte10,byte11,byte12,byte13
        byteRequest[10] = Integer.valueOf(0x00).byteValue();
        //数据值 byte9,byte10,byte11,byte12,byte13
        byteRequest[11] = Integer.valueOf(0x00).byteValue();
        //数据值 byte9,byte10,byte11,byte12,byte13
        byteRequest[12] = Integer.valueOf(0x00).byteValue();
        //数据值 byte9,byte10,byte11,byte12,byte13
        byteRequest[13] = Integer.valueOf(0x00).byteValue();
        int total = 0;
        for (int i = 0; i <= 13; i++) {
            total += (byteRequest[i] & 0xFF);
        }
        buffer = ByteBuffer.allocate(4); // 分配4字节空间
        buffer.putInt(total); // 写入int值
        byte[] byteArray = buffer.array();
        //校验和 把前面的数据加起来然后取最后一个字节 byte14
        byteRequest[14] = byteArray[3];
        //帧尾
        byteRequest[15] = Integer.valueOf(0x55).byteValue();
        String data = bytesToHex(byteRequest);
        return data;
    }

    /**
     * 斜顶指令解析
     * @param data
     * @return
     */
    public static SlantFeedbackMessage parseFromSlantCallback(String data) {
        SlantFeedbackMessage slantResponseBO = new SlantFeedbackMessage();
        slantResponseBO.setOriginalSlantResponse(data);
        if (StringUtils.isBlank(data) || data.length() != 32) {
            slantResponseBO.setCannotParserReason("content illegal,data length should be 32");
            return slantResponseBO;
        }
        String[] contentArray = new String[16];
        for (int i = 0; i < 16; i++) {
            contentArray[i] = data.substring(i * 2, i * 2 + 2);
        }
        if (!(contentArray[0].equalsIgnoreCase("aa") && contentArray[contentArray.length - 1].equalsIgnoreCase("55"))) {
            log.error("content illegal,data should start with aa and end with 55");
            slantResponseBO.setCannotParserReason("content illegal,data should start with aa and end with 55");
            return slantResponseBO;
        }
        if (!(contentArray[7].equals("21"))) {
            log.error("content illegal,data of index 7 should be 21");
            slantResponseBO.setCannotParserReason("content illegal,data of index 7 should be 21");
            return slantResponseBO;
        }
        byte state = Integer.valueOf(contentArray[9], 16).byteValue();
        boolean[] stateBooleanArray = byteToBitArray(state);
        byte leftError = Integer.valueOf(contentArray[10], 16).byteValue();
        boolean[] leftErrorBooleanArray = byteToBitArray(leftError);
        byte rightError = Integer.valueOf(contentArray[11], 16).byteValue();
        boolean[] rightErrorBooleanArray = byteToBitArray(rightError);
        //分析左侧斜顶机构
        boolean leftHasError = leftErrorBooleanArray[0] || leftErrorBooleanArray[1] || leftErrorBooleanArray[2];
        slantResponseBO.setLeftHasError(leftHasError);
        SlantState leftState;
        if (stateBooleanArray[0]) {
            if (stateBooleanArray[4]) {
                leftState = SlantState.AngledLift;
            } else {
                leftState = SlantState.LevelLift;
            }
        } else {
            leftState = SlantState.Running;
        }
        slantResponseBO.setLeftSlantState(leftState);
        slantResponseBO.setOpenLeftAutoDetect(stateBooleanArray[6]);
        //分析右侧斜顶机构
        boolean rightHasError = rightErrorBooleanArray[0] || rightErrorBooleanArray[1] || rightErrorBooleanArray[2];
        slantResponseBO.setRightHasError(rightHasError);
        SlantState rightState;
        if (stateBooleanArray[1]) {
            if (stateBooleanArray[5]) {
                rightState = SlantState.AngledLift;
            } else {
                rightState = SlantState.LevelLift;
            }
        } else {
            rightState = SlantState.Running;
        }
        slantResponseBO.setRightSlantState(rightState);
        slantResponseBO.setOpenRightAutoDetect(stateBooleanArray[7]);
        return slantResponseBO;
    }

    public static Integer getNextId(String key, int maxValue) {
        lockObject.putIfAbsent(key, key);
        synchronized (lockObject.get(key)) {
            Integer previousId = idMap.get(key);
            if (previousId == null || previousId.equals(maxValue)) {
                idMap.put(key, 0);
                return 0;
            }
            idMap.put(key, previousId + 1);
            return previousId + 1;
        }
    }

    /**
     * 字节数组转十六进制字符串
     */
    public static String bytesToHex(byte[] byteArray) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : byteArray) {
            hexString.append(String.format("%02X", b));
        }
        return hexString.toString();
    }

    public static boolean[] byteToBitArray(byte value) {
        boolean[] bits = new boolean[8];
        for (int i = 0; i < 8; i++) {
            bits[i] = (value & (1 << i)) != 0;
        }
        return bits;
    }

    public static String bitArrayToString(boolean[] bitArray) {
        StringBuilder stringBuilder = new StringBuilder("bitArray ");
        for (int i = 0; i < bitArray.length; i++) {
            boolean b = bitArray[i];
            stringBuilder.append("[");
            stringBuilder.append(i);
            stringBuilder.append("]");
            stringBuilder.append("=");
            stringBuilder.append(b ? "1" : "0");
            stringBuilder.append(" ");
        }
        return stringBuilder.toString();
    }

    public static byte[] hexToBytes(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }
}
